{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "9fc6205b",
   "metadata": {},
   "source": [
    "# Elastic QnA\n",
    "\n",
    "БД `Elasticsearch` может быть легко подключена к GigaChain. В данном примере рассмотрим, как можно использовать Elasticsearch для поиска ответов на вопросы по документам."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "51489529-5dcd-4b86-bda6-de0a39d8ffd1",
   "metadata": {},
   "source": [
    "## Установка"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1435c804-069d-4ade-9a7b-006b97b767c1",
   "metadata": {},
   "source": [
    "Нужно, чтобы у вас был доступ к Elasticsearch. Для этого можно использовать [Elastic Cloud](https://www.elastic.co/cloud/) или запустить его локально.\n",
    "\n",
    "```bash\n",
    "    docker run -p 9200:9200 -e \"discovery.type=single-node\" -e \"xpack.security.enabled=false\" -e \"xpack.security.http.ssl.enabled=false\" docker.elastic.co/elasticsearch/elasticsearch:8.9.0\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "1a737220",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# !pip install elasticsearch openai tiktoken gigachain"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e0dcc2f5",
   "metadata": {},
   "source": [
    "# Загрузка документов в БД"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6fafb73b-d6ec-4822-b161-edf0aaf5224a",
   "metadata": {},
   "source": [
    "## Индексация и загрузка в БД"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "7508276b",
   "metadata": {},
   "outputs": [],
   "source": [
    "import getpass\n",
    "import os\n",
    "\n",
    "from langchain.embeddings.openai import OpenAIEmbeddings\n",
    "from langchain.vectorstores import ElasticsearchStore\n",
    "\n",
    "os.environ[\"OPENAI_API_KEY\"] = getpass.getpass(\"OpenAI API Key:\")\n",
    "embeddings = OpenAIEmbeddings()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "72e89637",
   "metadata": {},
   "source": [
    "### Нарезаем документ на небольшие кусочки\n",
    "Документ - статья из Википедд о крушении Титаника. Размер статьи около 100 кб. Мы будем разрезать её на кусочки по 500 символов."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "f381f642",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total docs: 331\n"
     ]
    }
   ],
   "source": [
    "from langchain.document_loaders import TextLoader\n",
    "from langchain.text_splitter import (\n",
    "    CharacterTextSplitter,\n",
    "    RecursiveCharacterTextSplitter,\n",
    ")\n",
    "\n",
    "loader = TextLoader(\"../../modules/titanic_wiki_ru.txt\")\n",
    "documents = loader.load()\n",
    "text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=0)\n",
    "docs = text_splitter.split_documents(documents)\n",
    "\n",
    "print(f\"Total docs: {len(docs)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "21b1d6ff",
   "metadata": {},
   "source": [
    "### Загружаем все документы в Elastic, попутно вычисляя эмбединги"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "20ae1a74",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ObjectApiResponse({'_shards': {'total': 2, 'successful': 1, 'failed': 0}})"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# docs = retriever.get_relevant_documents(query=\"Титаник\", lang=\"ru\")\n",
    "db = ElasticsearchStore.from_documents(\n",
    "    docs,\n",
    "    embeddings,\n",
    "    es_url=\"http://localhost:9200\",\n",
    "    index_name=\"test-basic\",\n",
    ")\n",
    "\n",
    "db.client.indices.refresh(index=\"test-basic\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2670363b-3806-4c7e-b14d-90a4d5d2a200",
   "metadata": {},
   "source": [
    "### Question Answering on facts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "583a55ab",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chat_models.gigachat import GigaChat\n",
    "\n",
    "user = getpass.getpass(\"Giga user:\")\n",
    "password = getpass.getpass(\"Giga password:\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "b42d4c9f",
   "metadata": {},
   "outputs": [],
   "source": [
    "giga = GigaChat(profanity=False, credentials=...)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "51a33cc9-ec42-4afc-8a2d-3bfff476aa59",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from langchain.chains import RetrievalQA\n",
    "\n",
    "qa = RetrievalQA.from_llm(llm=giga, retriever=db.as_retriever(earch_kwargs={\"k\": 5}))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "ea537767-a8bf-4adf-ae03-b353c9145d58",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Q: В каком году утонул титаник?\n",
      "A: «Титаник» затонул в ночь с 14 на 15 апреля 1912 года.\n",
      "\n",
      "Q: Сколько человек погибло на титанике?\n",
      "A: По последним доступным данным, на борту «Титаника» погибло около 1500 человек.\n",
      "\n",
      "Q: Почему было так много жертв?\n",
      "A: Крушение \"Титаника\" стало одним из самых трагических событий в истории мореплавания. Причиной этого стали несколько факторов. Во-первых, корабль был построен без должной безопасности и не соответствовал современным стандартам. Во-вторых, он столкнулся с айсбергом во время сильного шторма, что привело к его разрушению и потере жизней всех пассажиров и экипажа. Кроме того, на борту находилось большое количество людей, которые не были должным образом подготовлены к такому большому количеству пассажиров и не имели достаточного количества спасательных средств. Все эти факторы вместе привели к гибели множества людей.\n",
      "\n",
      "Q: Какой корабль первым пришел на помощь?\n",
      "A: Первым на помощь пришел корабль \"Карпатия\".\n",
      "\n",
      "Q: Какова была мощность двигателей титаника?\n",
      "A: Мощность двигателей Титаника составляла около 2000 лошадиных сил каждый.\n",
      "\n",
      "Q: Чем отличались каюты разных классов?\n",
      "A: В зависимости от класса, каюты могли отличаться различными удобствами и деталями интерьера. Например, в каютах первого класса могли быть установлены большие окна для лучшего обзора окружающей местности, а также дополнительные удобства, такие как мраморные раковины и унитазы с системой смыва. В каютах второго класса могли быть установлены более простые кровати и мебель, а также меньше окон для сохранения приватности. Кроме того, в некоторых случаях, например, при перевозке грузов, каюты могли быть переоборудованы для перевозки большего количества пассажиров.\n",
      "\n",
      "Q: Что там было с биноклем?\n",
      "A: В ящике в вороньем гнезде отсутствовали бинокли. Второй помощник Дэвид Блэр в Саутгемптоне положил бинокли в сейф в своей каюте, но после списания на берег забыл передать ключ Чарльзу Лайтоллеру, который не смог найти другие бинокли.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "questions = [\n",
    "    \"В каком году утонул титаник?\",\n",
    "    \"Сколько человек погибло на титанике?\",\n",
    "    \"Почему было так много жертв?\",\n",
    "    \"Какой корабль первым пришел на помощь?\",\n",
    "    \"Какова была мощность двигателей титаника?\",\n",
    "    \"Чем отличались каюты разных классов?\",\n",
    "    \"Что там было с биноклем?\",\n",
    "]\n",
    "chat_history = []\n",
    "\n",
    "for question in questions:\n",
    "    result = qa(question)\n",
    "    print(f\"Q: {question}\")\n",
    "    print(f\"A: {result['result']}\\n\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
